package com.example.widget_lib.widget.progress.circle;

import com.example.widget_lib.ResourceTable;
import com.example.widget_lib.utils.AttrUtils;
import com.example.widget_lib.utils.FormatUtil;
import com.example.widget_lib.utils.LogUtil;
import com.example.widget_lib.utils.PxUtil;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.*;
import ohos.app.Context;
import ohos.global.resource.solidxml.TypedAttribute;

import java.text.DecimalFormat;
import java.util.HashMap;

/**
 * 自定义圆环进度条
 * 1.支持外环宽度大于内环
 * 2.支持中间文本显示
 * 3.支持圆环进度动画
 * 4.支持圆环底部小三角
 */
public class CircleProgressBarView extends Component implements Component.DrawTask {
    private final String TAG = this.getClass().getSimpleName();
    private Context mContext;

    /**
     * 默认进度圆环渐变色值集合
     */
    private int[] mDefColors = {Color.rgb(101, 226, 175), Color.rgb(88, 181, 250)};

    /**
     * 100%进度圆环渐变色值集合
     */
    private int[] mEndColors = {Color.rgb(255, 196, 0), Color.rgb(255, 110, 77)};
    private int mStartColor = Color.rgb(101, 226, 175);
    private int mEndColor = Color.rgb(88, 181, 250);

    //圆心x坐标
    private float centerX, centerY;
    // 圆的半径
    private float radius;
    // 进度
    private float mProgress;
    // 当前进度
    private float currentProgress;
    // 圆形进度条底色画笔
    private Paint circleBgPaint;
    // 圆形进度条进度画笔
    private Paint progressPaint;
    // 进度条背景颜色
    private int circleBgColor = Color.rgb(225, 229, 232);
    // 进度条颜色
    private int progressColor = Color.rgb(255, 0, 0);
    // 默认圆环的宽度
    private int defaultStrokeWidth = 20;
    // 圆形背景画笔宽度
    private int circleBgStrokeWidth = defaultStrokeWidth;
    // 圆形进度画笔宽度
    private int progressStrokeWidth = defaultStrokeWidth;
    private int lineWidth = (int) PxUtil.vp2px(1);
    private boolean isDrawCenterProgressText;
    private int centerProgressTextSize = 23;
    private int centerProgressTextColor = Color.rgb(128, 128, 128);
    private int targetTextSize = (int) PxUtil.fp2px(12);
    private int targetTextColor = Color.rgb(128, 128, 128);
    private int targetNumSize = 20;
    private int targetNumColor = Color.rgb(0, 0, 0);
    private int lineColor = Color.rgb(128, 128, 128);

    //画笔
    private Paint centerProgressTextPaint = new Paint();
    private Paint trainPaint = new Paint();
    private Paint linePaint = new Paint();
    private Paint targetTextPaint = new Paint();
    private Paint targetNumPaint = new Paint();

    // 扇形所在矩形
    private RectFloat rectF = new RectFloat();
    //进度动画
    private AnimatorValue progressAnimator;
    //动画执行时间
    private int duration = 1000;
    // 动画延时启动时间
    private int startDelay = 500;

    private ProgressListener progressListener;
    private String targetText;
    private String targetNum = "0";
    private int dp1, dp2, dp4, dp5, dp6, dp7, dp8,dp10, dp30;

    public CircleProgressBarView(Context context) {
        this(context, null);
    }

    public CircleProgressBarView(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    public CircleProgressBarView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        mContext = context;
        dp1 = (int) PxUtil.vp2px(1);
        dp2 = (int) PxUtil.vp2px(2);
        dp4 = (int) PxUtil.vp2px(4);
        dp5 = (int) PxUtil.vp2px(5);
        dp6 = (int) PxUtil.vp2px(6);
        dp7 = (int) PxUtil.vp2px(7);
        dp8 = (int) PxUtil.vp2px(8);
        dp10 = (int) PxUtil.vp2px(10);
        dp30 = (int) PxUtil.vp2px(30);
        addDrawTask(this);
        getAttr(attrSet);
        initPaint();
    }

    private void getAttr(AttrSet attrSet) {
        centerProgressTextColor = AttrUtils.getColorFromAttr(attrSet,"centerProgressTextColor", mEndColor);
        centerProgressTextSize = AttrUtils.getDimensionFromAttr(attrSet,"centerProgressTextSize", centerProgressTextSize);
        circleBgStrokeWidth = AttrUtils.getDimensionFromAttr(attrSet,"circleBgStrokeWidth", defaultStrokeWidth);
        isDrawCenterProgressText = AttrUtils.getBooleanFromAttr(attrSet,"isDrawCenterProgressText", false);
        progressStrokeWidth = AttrUtils.getDimensionFromAttr(attrSet,"progressStrokeWidth", defaultStrokeWidth);
        targetNumSize = AttrUtils.getDimensionFromAttr(attrSet,"targetNumSize", 20);
        targetTextColor = AttrUtils.getColorFromAttr(attrSet,"targetTextColor", targetTextColor);
        targetText = AttrUtils.getStringFromAttr(attrSet,"target_text", "");

        LogUtil.loge(TAG,
                "centerProgressTextColor: " + centerProgressTextColor
                        + " centerProgressTextSize: " + centerProgressTextSize
                        + " circleBgStrokeWidth: " + circleBgStrokeWidth
                        + " isDrawCenterProgressText: " + isDrawCenterProgressText
                        + " progressStrokeWidth: " + progressStrokeWidth
                        + " targetNumSize: " + targetNumSize
                        + " targetTextColor: " + targetTextColor
                        + " targetText: " + targetText
        );
    }

    private void initPaint() {
        circleBgPaint = getPaint(circleBgStrokeWidth, circleBgColor);
        progressPaint = getPaint(progressStrokeWidth, progressColor);
        trainPaint = getPaint((int) PxUtil.vp2px(1), progressColor);
        trainPaint.setStyle(Paint.Style.FILL_STYLE);

        linePaint = getPaint(lineWidth, lineColor);
        // 目标文本画笔配置
        targetTextPaint = new Paint();
        targetTextPaint.setAntiAlias(true);
        targetTextPaint.setTextSize(targetTextSize);
        targetTextPaint.setColor(new Color(targetTextColor));
        targetTextPaint.setTextAlign(TextAlignment.CENTER);

        // 目标数字画笔配置
        targetNumPaint = new Paint();
        targetNumPaint.setAntiAlias(true);
        targetNumPaint.setTextSize(targetNumSize);
        targetNumPaint.setColor(new Color(targetNumColor));
        targetNumPaint.setTextAlign(TextAlignment.CENTER);

        // 中间文本画笔配置
        centerProgressTextPaint = new Paint();
        centerProgressTextPaint.setAntiAlias(true);
        centerProgressTextPaint.setTextSize(centerProgressTextSize);
        centerProgressTextPaint.setColor(new Color(centerProgressTextColor));
        centerProgressTextPaint.setTextAlign(TextAlignment.CENTER);
    }

    private Paint getPaint(int strokeWidth, int color) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(strokeWidth);
        paint.setColor(new Color(color));
        paint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        paint.setStyle(Paint.Style.STROKE_STYLE);
        return paint;
    }

    public void setCenterProgressTextColor(int color) {
        this.centerProgressTextColor = color;
        centerProgressTextPaint.setColor(new Color(color));
    }

    private void initAfterOnSizeChanged() {
        centerX = getWidth() / 2;
        centerY = getHeight() / 2;

        // 半径再缩小点，给小三角形空出距离
        radius = Math.min(getWidth(), getHeight()) / 2 - Math.max(circleBgStrokeWidth, progressStrokeWidth) - dp4;
        LogUtil.loge(TAG, "centerX:" + centerX
                + "centerY:" + centerY
                + "Width:" + getWidth()
                + "Height:" + getHeight()
                + "radius:" + radius
        );
        rectF.left = centerX - radius;
        rectF.top = centerY - radius;
        rectF.right = centerX + radius;
        rectF.bottom = centerY + radius;
        trainPaint.setColor(new Color(circleBgColor));

        configShader();
    }

    private LinearShader mShader;

    private void configShader() {
        // 清空画笔
        progressPaint.setShader(null, Paint.ShaderType.LINEAR_SHADER);
        if (mProgress >= 100) {
            Point[] points = new Point[]{
                    new Point(centerX, 0),
                    new Point(centerX, getHeight())
            };
            Color[] colors = new Color[mEndColors.length];
            for (int i = 0; i < mEndColors.length; i++) {
                colors[i] = new Color(mEndColors[i]);
            }
            mShader = new LinearShader(points, null, colors, Shader.TileMode.CLAMP_TILEMODE);
        } else {
            Point[] points = new Point[]{
                    new Point(centerX, 0),
                    new Point(centerX, getHeight())
            };
            Color[] colors = new Color[mDefColors.length];
            for (int i = 0; i < mDefColors.length; i++) {
                colors[i] = new Color(mDefColors[i]);
            }
            mShader = new LinearShader(points, null, colors, Shader.TileMode.CLAMP_TILEMODE);
        }
        progressPaint.setShader(mShader, Paint.ShaderType.LINEAR_SHADER);
    }

    private boolean proAnimIsEnd = false;

    private void initAnimation() {
        proAnimIsEnd = false;
        progressAnimator = new AnimatorValue();
//        progressAnimator = AnimatorValue.ofFloat(0, mProgress);
        progressAnimator.setDuration(duration);
        progressAnimator.setDelay(startDelay);
        progressAnimator.setCurveType(Animator.CurveType.LINEAR);
//        progressAnimator.setInterpolator(new LinearInterpolator());
        progressAnimator.setValueUpdateListener((valueAnimator, percent) -> {
//            float value = (float) valueAnimator.getAnimatedValue();
//            mProgress = value* mProgress;
            float value = percent * mProgress;
            currentProgress = value * 360 / 100;
            if (progressListener != null) {
                progressListener.currentProgressListener(FormatUtil.roundTwo(value));
            }
            invalidate();
        });
        progressAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                proAnimIsEnd = true;
                invalidate();
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
    }

    public void setTargetNum(String num) {
        targetNum = num;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        initAfterOnSizeChanged();
        LogUtil.loge(TAG, "centerX = " + centerX + "->centerY = "
                + centerY + "->mProgress = " + mProgress);
        canvas.drawCircle(centerX, centerY, radius, circleBgPaint);
        Arc arc = new Arc(-90, currentProgress, false);
        canvas.drawArc(rectF, arc, progressPaint);
        if (isDrawCenterProgressText) {
            drawCenterProgressText(canvas, formatNum(mProgress) + "%");
        }
        if (proAnimIsEnd) {
            drawTriangle(canvas);
        }
    }

    private void drawCenterProgressText(Canvas canvas, String currentProgress) {
        Paint.FontMetrics fontMetrics1 = centerProgressTextPaint.getFontMetrics();
        int baseline = (int) ((rectF.bottom + rectF.top - fontMetrics1.bottom - fontMetrics1.top) / 2);
        //文字绘制到整个布局的中心位置
        Point startPoint = new Point(centerX - dp30, centerY);
        Point endPoint = new Point(centerX + dp30, centerY);
        canvas.drawLine(startPoint, endPoint, linePaint);

        canvas.drawText(centerProgressTextPaint, currentProgress, centerX, centerY - dp5);

        Paint.FontMetrics fontMetrics2 = targetNumPaint.getFontMetrics();
        int baseline2 = (int) (baseline + (fontMetrics2.bottom - fontMetrics2.top));
        LogUtil.loge(TAG, "baseline: " + baseline + "baseline2: " + baseline2);
        canvas.drawText(targetTextPaint, targetText, centerX, baseline + dp7);

        canvas.drawText(targetNumPaint, targetNum, centerX, baseline2 + dp5);
    }

    /**
     * 绘制三角形
     *
     * @param canvas
     */
    private void drawTriangle(Canvas canvas) {
        Path path = new Path();
        Point pf1, pf2, pf3;
        LogUtil.loge(TAG, "绘制小三角 mProgress = " + mProgress);
        if (mProgress < 49) {
            trainPaint.setColor(new Color(circleBgColor));
            pf1 = new Point(centerX - dp10, centerY * 2 - progressStrokeWidth - dp6);
            pf2 = new Point(centerX - dp1, getHeight());
            pf3 = new Point(centerX + dp10, centerY * 2 - progressStrokeWidth - dp6);
        } else if (mProgress >= 49 && mProgress < 51) {
            float[] positions;
            int pro = (int) (mProgress * 100);
            if (mProgress >= 49 && pro < 49.2 * 100) {
                positions = new float[]{0.39f, 0.39f};
                LogUtil.loge(TAG, "阶段1 -> pro = " + pro);
            } else if (pro >= 49.2 * 100 && pro < 49.4 * 100) {
                positions = new float[]{0.46f, 0.46f};
                LogUtil.loge(TAG, "阶段2");
            } else if (pro >= 49.4 * 100 && pro < 49.6 * 100) {
                positions = new float[]{0.5f, 0.5f};
                LogUtil.loge(TAG, "阶段3 -> pro = " + pro);
            } else if (pro >= 49.6 * 100 && pro < 49.8 * 100) {
                positions = new float[]{0.62f, 0.38f};
                LogUtil.loge(TAG, "阶段4 -> pro = " + pro);
            } else if (pro >= 49.8 * 100 && pro < 50 * 100) {
                positions = new float[]{0.64f, 0.36f};
                LogUtil.loge(TAG, "阶段5 -> pro = " + pro);
            } else if (pro >= 50 * 100 && pro < 50.2 * 100) {
                positions = new float[]{0.7f, 0.3f};
                LogUtil.loge(TAG, "阶段6 -> pro = " + pro);
            } else if (pro >= 50.2 * 100 && pro < 50.4 * 100) {
                positions = new float[]{0.75f, 0.25f};
                LogUtil.loge(TAG, "阶段7 -> pro = " + pro);
            } else if (pro >= 50.4 * 100 && pro < 50.6 * 100) {
                positions = new float[]{0.8f, 0.2f};
                LogUtil.loge(TAG, "阶段8 -> pro = " + pro);
            } else if (pro >= 50.6 * 100 && pro <= 50.8 * 100) {
                positions = new float[]{0.9f, 0.1f};
                LogUtil.loge(TAG, "阶段9 -> pro = " + pro);
            } else {
                positions = new float[]{1.0f, 0.f};
                LogUtil.loge(TAG, "阶段 else");
            }
            Point[] points = {new Point(centerX + dp10, 0), new Point(centerX - dp10, 0)};
            Color[] colors = {new Color(Color.rgb(88, 181, 250)), new Color(Color.rgb(225, 229, 232))};
            LinearShader triangleGdt = new LinearShader(points, positions, colors, Shader.TileMode.CLAMP_TILEMODE);
            trainPaint.setShader(triangleGdt, Paint.ShaderType.LINEAR_SHADER);
            pf1 = new Point(centerX - dp10, centerY * 2 - progressStrokeWidth - dp6);
            pf2 = new Point(centerX - dp1, getHeight());
            pf3 = new Point(centerX + dp10, centerY * 2 - progressStrokeWidth - dp6);
        } else {
            trainPaint.setShader(null, Paint.ShaderType.LINEAR_SHADER); // 不要忘记清空着色器，不能设置的color没有效果，会优先显示shader
            if (mProgress >= 100) {
                trainPaint.setColor(new Color(mEndColors[mEndColors.length - 1]));
            } else {
                trainPaint.setColor(new Color(mDefColors[mDefColors.length - 1]));
            }
            pf1 = new Point(centerX - dp10, centerY * 2 - progressStrokeWidth - dp6);
            pf2 = new Point(centerX - dp1, getHeight());
            pf3 = new Point(centerX + dp10, centerY * 2 - progressStrokeWidth - dp6);
        }
        path.moveTo(pf1.getPointX(), pf1.getPointY());
        path.lineTo(pf2.getPointX(), pf2.getPointY());
        path.lineTo(pf3.getPointX(), pf3.getPointY());
        canvas.drawPath(path, trainPaint);
        path.reset();
    }


    @Override
    public void release() {
        super.release();
        if (progressAnimator != null) {
            progressAnimator.cancel();
        }
    }

    public void startProgressAnimation() {
        progressAnimator.start();
    }

    public void pauseProgressAnimation() {
        progressAnimator.pause();
    }

    public void resumeProgressAnimation() {
        progressAnimator.resume();
    }

    public void stopProgressAnimation() {
        progressAnimator.end();
    }

    /**
     * 传入一个进度值，从0到progress动画变化
     *
     * @param progress
     * @return 返回CircleProgressBarView
     */
    public CircleProgressBarView setProgressWithAnimation(float progress) {
//        if (progress <= 0f || String.valueOf(progress).equals(String.valueOf(Float.NaN))) {
        if (progress <= 0f || Float.isNaN(progress)) {
            setCurrentProgress(0f, true);
            return this;
        }
        mProgress = progress;
//        if (progress >= 100) {
//            configShader();
//        }else{
        configShader();
//        }
        initAnimation();
        startProgressAnimation();
        return this;
    }

    /**
     * 实时进度，适用于下载进度回调时候之类的场景
     *
     * @param progress
     * @return CircleProgressBarView
     */
    public CircleProgressBarView setCurrentProgress(float progress) {
        mProgress = progress;
        currentProgress = progress * 360 / 100;
        if (progress >= 100) {
            configShader();
        }
        invalidate();
        return this;
    }


    /**
     * 实时进度，适用于下载进度回调时候之类的场景
     *
     * @param progress
     * @param isArrow  是否有小箭头
     * @return  CircleProgressBarView
     */
    public CircleProgressBarView setCurrentProgress(float progress, boolean isArrow) {
        proAnimIsEnd = isArrow;
        setCurrentProgress(progress);
        return this;
    }

    /**
     * 格式化数字(保留两位小数)
     *
     * @param money
     * @return 格式化数字(保留两位小数)
     */
    public static String formatNum(float money) {
        if (((int) money * 100) == (int) (money * 100)) {
            //如果是一个整数
            return String.valueOf((int) money);
        }
        DecimalFormat format = new DecimalFormat("0.00");
        return format.format(money);
    }

    public interface ProgressListener {
        void currentProgressListener(float currentProgress);
    }

    public CircleProgressBarView setProgressListener(ProgressListener listener) {
        progressListener = listener;
        return this;
    }
}
